package ch.fhnw.qualiscan.application.models;

import java.util.List;

import ch.fhnw.qualiscan.Config;
import ch.fhnw.qualiscan.core.Model;
import ch.fhnw.qualiscan.core.db.pojos.Answer;
import ch.fhnw.qualiscan.core.db.pojos.BestPractice;
import ch.fhnw.qualiscan.core.db.pojos.Confidence;
import ch.fhnw.qualiscan.core.db.pojos.Domain;
import ch.fhnw.qualiscan.core.db.pojos.DomainDescription;
import ch.fhnw.qualiscan.core.db.pojos.DomainText;
import ch.fhnw.qualiscan.core.db.pojos.Language;
import ch.fhnw.qualiscan.core.db.pojos.Questionnaire;
import ch.fhnw.qualiscan.core.db.pojos.Role;
import ch.fhnw.qualiscan.core.db.pojos.Survey;
import ch.fhnw.qualiscan.core.db.pojos.SurveyUserRole;
import ch.fhnw.qualiscan.core.db.pojos.User;

/**
 * 
 * @author Kevin Mettenberger
 *
 */
public class DomainModel extends Model {
	
	/**
	 * Gets the domain text for a specified domain
	 * 
	 * @param domain
	 * @param language
	 * @return the domain text.
	 */
	public DomainText getDomainText(Domain domain, Language language) {
		
		DomainText dt = (DomainText) hibernateSession.getSession().createQuery("from DomainText as dt where dt.domain = :domain and dt.language = :language")
        .setParameter("domain", domain)
        .setParameter("language", language)
        .uniqueResult();
		
		if (dt == null) {
			Language l = new Language();
			l.setId(Config.ENGLISH_ID);
			
			dt = (DomainText) hibernateSession.getSession().createQuery("from DomainText as dt where dt.domain = :domain and dt.language = :language")
	        .setParameter("domain", domain)
	        .setParameter("language", l)
	        .uniqueResult();
			
		}
		return dt;
	}
	
	/**
	 * Gets the domain description for a specified domain
	 * 
	 * @param domain
	 * @param language
	 * @return the domain text.
	 */
	public DomainDescription getDomainDescription(Domain domain, Language language) {
		
		DomainDescription dd = (DomainDescription) hibernateSession.getSession().createQuery("from DomainDescription as dd where dd.domain = :domain and dd.language = :language")
        .setParameter("domain", domain)
        .setParameter("language", language)
        .uniqueResult();
		if (dd == null) {
			dd = new DomainDescription();
			dd.setText("");
		}
		
		return dd;
	}
	
	/**
	 * This function loads all domains in the system.
	 * @return list with all domain objects in it.
	 */
	public List<Domain> getDomains() {
		List<Domain> domains = hibernateSession.getSession().createQuery("from Domain as domain").list();
		return domains;
	}

	/**
	 * Gets the Domain object for the specified id.
	 * @param domainId the id of the domain.
	 * @return returns the the domain object if it exists. Else null.
	 */
	public Domain getDomainById(int domainId) {
		Domain d = (Domain) hibernateSession.getSession().get(Domain.class, domainId);
		if (d != null) {
			return d;
		}
		return null;
	}
	
	/**
	 * Gets the confidence of a domain for a specified survey and user.
	 * @param survey the survey
	 * @param domain the domain
	 * @param user the user
	 * @return returns the confidence if there's one saved in the database, else null.
	 */
	public Confidence getConfidenceOfDomain(SurveyUserRole sur, Domain domain) {
		Confidence c = (Confidence)hibernateSession.getSession().createQuery("from Confidence as c where sur = :sur and domain = :domain")
		.setParameter("sur", sur)
		.setParameter("domain", domain)
		.uniqueResult();
		
		return c;
	}
	
	/**
	 * Stores the confidence of a domain in the db.
	 * @param confidence the confidence object to be saved.
	 * @param domain the associated domain.
	 */
	public void saveConfidenceOfDomain(Confidence confidence, Domain domain) {
		hibernateSession.getSession().save(confidence);
		Domain d = (Domain)hibernateSession.getSession().get(Domain.class, domain.getId());
		d.addConfidence(confidence);
		
		hibernateSession.getSession().flush();
		hibernateSession.closeSession();
		
	}
	
	/**
	 * Update a confidence object in the database.
	 * @param confidence the confidence object to be updated.
	 */
	public void updateConfidenceOfDomain(Confidence confidence) {
		hibernateSession.getSession().update(confidence);
		hibernateSession.closeSession();
	}
	
	/**
	 * Gets the best practice of a domain for a specified survey and user.
	 * @param survey the survey
	 * @param domain the domain
	 * @param user the user
	 * @return returns the best practice if there's one saved in the database, else null.
	 */
	public BestPractice getBestPracticeOfDomain(SurveyUserRole sur, Domain domain) {
		BestPractice bp = (BestPractice)hibernateSession.getSession().createQuery("from BestPractice as bp where sur = :sur and domain = :domain")
		.setParameter("sur", sur)
		.setParameter("domain", domain)
		.uniqueResult();
		
		return bp;
	}
	
	/**
	 * Stores the best practice of a domain in the db.
	 * @param bestPractice the best practice object to be saved.
	 * @param domain the associated domain.
	 */
	public void saveBestPracticeOfDomain(BestPractice bestPractice, Domain domain) {
		hibernateSession.getSession().save(bestPractice);
		Domain d = (Domain)hibernateSession.getSession().get(Domain.class, domain.getId());
		d.addBestpractice(bestPractice);
		
		hibernateSession.getSession().flush();
		
		
	}
	
	/**
	 * Update a best practice object in the database.
	 * @param bestpractice the BestPractice object to be updated.
	 */
	public void updateBestPracticeOfDomain(BestPractice bestpractice) {
		hibernateSession.getSession().update(bestpractice);
		hibernateSession.getSession().flush();
	}
	
	/**
	 * Returns the amount of answers there are already in the database
	 * @param domain the domain
	 * @param survey the survey
	 * @return the number of answers
	 */
	public int getNumberOfAnswersForDomain(Domain domain, Survey survey) {
		@SuppressWarnings("unchecked")
		List<Answer> answerList = hibernateSession.getSession().createQuery("from Answer as a where survey = :survey and domain = :domain")
		.setParameter("survey", survey)
		.setParameter("domain", domain)
		.list();
		
		return answerList.size();
	}
	
	/**
	 * Returns the amount of answers there are already in the database of a user
	 * @param domain the domain	
	 * @param survey the survey
	 * @param user the user
	 * @return the number of answers
	 */
	public int getNumberOfAnswersForSurAndDomain(SurveyUserRole sur, Domain domain) {
		@SuppressWarnings("unchecked")
		List<Answer> answerList = hibernateSession.getSession().createQuery("from Answer as a where sur = :sur and domain = :domain")
		.setParameter("domain", domain)
		.setParameter("sur", sur)
		.list();
		
		return answerList.size();
	}
	
	/**
	 * Gets the average confidence of the participants for a specified domain, survey and role.
	 * @param domain a domain
	 * @param survey a survey
	 * @param role a role
	 * @return average of confidences
	 */
	public int getAverageConfidenceForDomain(Domain domain, Survey survey, Role role) {
		@SuppressWarnings("unchecked")
		List<Confidence> confidenceList = hibernateSession.getSession().createQuery("from Confidence as c where survey = :survey and domain = :domain and (sur.role = :role or sur.fillOutRole = :filloutrole)")
		.setParameter("survey", survey)
		.setParameter("domain", domain)
		.setParameter("role", role)
		.setParameter("filloutrole", role)
		.list();
		
		int counter = 0;
		int confidenceSum = 0;
		int confidenceAverage = 0;
		for (int i = 0; i < confidenceList.size(); i++) {
			counter++;
			confidenceSum  = confidenceSum + confidenceList.get(i).getConfidence();
			
		}
		if (counter > 0) {
			confidenceAverage=confidenceSum/counter;
		}
		
		return confidenceAverage;
	}
	
	/**
	 * Gets a List of all Best Practices for a domain
	 * @param survey the survey
	 * @param domain the domain
	 * @return List containing BestPractices pojos
	 */
	public List<BestPractice> getBestPractices(Survey survey, Domain domain) {
		List<BestPractice> bpList = hibernateSession.getSession().createQuery("from BestPractice as bp where survey = :survey and domain = :domain and bestpractice != ''")
		.setParameter("survey", survey)
		.setParameter("domain", domain)
		.list();
		
		
		return bpList;
	}

   
}
